package main

import (
	"github.com/garyburd/redigo/redis"
	"github.com/ngaut/log"
	"github.com/shopspring/decimal"
	"global/structs"
	"server/ote/model"
	"sort"
	"time"
)

type Handler interface {
	handler(trust structs.TrustCoin, tType structs.TaskType, worker *Worker)
}

// 处理主动单是买单的委托单
type BuyHandler struct{
	name 				string
	doneWaiting 		[]trustItem
	startTime 			time.Time
	ctx 				*Context
}

func (self *BuyHandler) handler(trust structs.TrustCoin, tType structs.TaskType, worker *Worker) {
	self.name = worker.coinPair.Name
	if tType == structs.TASK_BUY {
		self.handlerBuy(trust, tType, worker)
	} else {
		handlerCancel(trust, tType, worker)
	}
}

func (self *BuyHandler) handlerBuy(trust structs.TrustCoin, tType structs.TaskType, worker *Worker)  {

	self.logInfo("------ Start Handler Buy Trust ------")
	self.logInfo("active trust info(tid: %d, uid: %d, number_available: %s, price: %s)", trust.Id, trust.Uid, trust.NumberAvailable, trust.Price)

	self.ctx = worker.ctx
	self.startTime = time.Now()

	conn := worker.ctx.GetOteRedis().Get()
	results := structs.NewResults(worker.coinPair.CoinFrom, worker.coinPair.CoinTo, structs.TASK_BUY)

	var err error
	var cacheOptSuccess bool
	self.doneWaiting = make([]trustItem, 0)

	defer func() {
		// 失败保护，如果Redis操作失败导致回滚，将该条委托申请加入待匹配列表
		dbHandler := NewHandlerDB(worker.coinPair)
		if !cacheOptSuccess {
			oteLog := NewOteLog(results, tType)
			if err != nil {
				oteLog.ErrorCode = model.OTE_LOG_ERRCODE_REDIS
				oteLog.ErrorMsg = err.Error()
			}

			if _, err := dbHandler.SaveOteLog(oteLog); err != nil {
				self.logError("save ote log error, msg: %s", err.Error())
			}

			_, err := addTrustToWaitWithMulti(conn, structs.TASK_BUY, worker.coinPair.Name, trust.Id, trust.Price)
			if err != nil {
				data, _ := resultToString(results)
				self.logError("redis rollback and add buy trust to wait failed, tid: %d, result: %v", trust.Id, data)
			}

			// 被动单删除的部分也会添加回去
			for _, item := range self.doneWaiting {
				_, err := addTrustToWaitWithMulti(conn, structs.TASK_SALE, worker.coinPair.Name, item.Id, item.Price.StringFixedBank(10))
				if err != nil {
					self.logError("redis rollback and add sale trust to wait failed, tid: %d, passiveId: %v, err: %v", trust.Id, item.Id, err)
				}
			}
		}

		// 将订单状态修改为 is_new = 0
		if cacheOptSuccess && results.AddActiveTrustToSet {
			if _, err := dbHandler.SetTrustCoinIsNewToOld(results.ActiveTrust.TrustId); err != nil {
				self.logError("set trust coin to old status failed, err: %s", err.Error())
			}
		}

		conn.Close()

		self.logInfo("end handler the trust, take time: %s", time.Since(self.startTime).String())
		self.logInfo("------ End Handler Sale Trust ------")
	}()

	activeResult := new(structs.OneTrust)
	activeAccount := new(structs.Account)

	activeResult.TrustId = trust.Id
	activeResult.Uid = trust.Uid
	activeResult.TrustDealStatus = structs.TRUST_STATUS_NOT
	activeResult.OriginalTrustCoin = copyWithStruct(trust)

	results.ActiveTrust = activeResult
	results.ActiveAccount = activeAccount

	err = self.doTrust(conn, trust, results, worker.coinPair)
	if err != nil {
		self.logError("do trust error, msg: %s", err.Error())
	}

	if results.AddActiveTrustToSet || !results.IsDealed {
		// 添加委托单到买家SET
		_, err = addTrustToWaitWithoutMulti(conn, structs.TASK_BUY, worker.coinPair.Name, trust.Id, trust.Price)
		if err != nil {
			self.logError("save trust buy error, tid: %d, msg: %s", trust.Id, err.Error())
		}
		self.logInfo("save trust buy success. tid: %d", trust.Id)
		cacheOptSuccess = true
		return
	}

	conn.Do("MULTI")

	// 1. 主动单
	if results.ActiveTrust.TrustDealStatus == structs.TRUST_STATUS_PARTIALLY {
		// 部分交易
		// 添加到 redis wait set
		if _, err = addTrustToWaitWithMulti(conn, structs.TASK_BUY,
			worker.coinPair.Name, trust.Id, trust.Price); err != nil {
			self.logError("set trust buy error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}
		self.logInfo("add trust to wait success, tid: %d", results.ActiveTrust.TrustId)

		// modify detail info
		if _, err = updateTrustAndUserDetailAndWithMulti(conn, worker.coinPair.Name, structs.TASK_BUY,
			trust.Id, trust.Uid, results.ActiveTrust.TrustCoin); err != nil {
			self.logError("update trust and user detail error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}
		self.logInfo("update trust detail success, tid: %d", results.ActiveTrust.TrustId)

	} else {
		// 全部交易
		if _, err = removeTrustDetailWithMulti(conn, worker.coinPair.Name, structs.TASK_BUY,
			trust.Id, trust.Uid); err != nil {
			self.logError("remove trust detail error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}

		saveTrustToHistoryDone(conn, worker.coinPair.Name, results.ActiveTrust.Uid, results.ActiveTrust.TrustCoin)
		self.logInfo("remove trust from wait, tid: %d", trust.Id)
	}

	// 2. 被动单
	for _, passiveTrust := range results.PassiveTrusts {
		if passiveTrust.TrustDealStatus == structs.TRUST_STATUS_PARTIALLY {
			// 被动单部分成交
			if _, err = updateTrustAndUserDetailAndWithMulti(conn, worker.coinPair.Name, structs.TASK_SALE,
				passiveTrust.TrustId, passiveTrust.Uid, passiveTrust.TrustCoin); err != nil {
				self.logError("update passive trust user detail error, msg: %s", err.Error())
				conn.Do("DISCARD")
				return
			}
			self.logInfo("update passive trust success, tid: %d, status: %d", passiveTrust.TrustId, model.Status_Partially)
		} else {
			// 被动单全部成交
			if _, err = removeTrustDetailWithMulti(conn, worker.coinPair.Name, structs.TASK_SALE,
				passiveTrust.TrustId, passiveTrust.Uid); err != nil {
				self.logError("remove trust detail error, msg: %s", err.Error())
				conn.Do("DISCARD")
				return
			}
			self.logInfo("remove passive trust success, tid: %d, status: %d", passiveTrust.TrustId, model.Status_All)

			saveTrustToHistoryDone(conn, worker.coinPair.Name, passiveTrust.Uid, passiveTrust.TrustCoin)
		}
	}

	conn.Do("EXEC")

	cacheOptSuccess = true
	results.RedisOptSuccess = true

	worker.handlerResult(results)
	// worker.result <- results
}

func (self *BuyHandler) loop(conn redis.Conn, trust *structs.TrustCoin, result *structs.Results, pair structs.CoinPair) error {

	trustNumber, _ := decimal.NewFromString(trust.Number)
	trustAvailable, _ := decimal.NewFromString(trust.NumberAvailable)
	trustPrice, _ := decimal.NewFromString(trust.Price)

	// 费率转换成 decimal.Decimal 数据类型
	sellRate, _ := decimal.NewFromString(pair.TradeSaleRate)
	buyRate, _ := decimal.NewFromString(pair.TradeBuyRate)

	self.logInfo("buy rate: %s, sale rate: %s", pair.TradeBuyRate, pair.TradeSaleRate)

	items, err := getMatchedSaleTrustsFromRedis(conn, trust.Price, pair.Name)
	if err != nil {
		self.logError("no matched sale items, getItems error, tid: %d, msg: %s", trust.Id, err.Error())
		return err
	}

	if len(items) == 0 {
		self.logInfo("no matched sale items, return and save to wait list, tid: %v", trust.Id)
		return nil
	}

	// 排序
	sort.Slice(items, func(i, j int) bool {
		if items[i].Price.Equal(items[j].Price) {
			return items[i].Id < items[j].Id
		}
		return items[i].Price.Cmp(items[j].Price) == -1
	})

	self.logInfo("get sale trust from wait list success, len: %d", len(items))

	counter := 0
	for _, item := range items {
		counter++
		self.logInfo(">>>>>> the %d times in loop <<<<<<", counter)

		seller, err := getTrustDetailFromRedis(conn, structs.TASK_SALE, pair.Name, item.Id)
		if err != nil {
			self.logError("get trust detail from redis error, msg: %s", err.Error())
			continue
		}

		self.logInfo("get sale trust info tid: %d, uid: %d, number: %s, number_available: %s, price: %s, status: %d",
			seller.Id, seller.Uid, seller.Number, seller.NumberAvailable, seller.Price, seller.Status)

		if seller.Id == 0 || seller.Status == model.Status_All || seller.Status == model.Status_Revoke {
			removeTrustFromWaitWithoutMulti(conn, structs.TASK_SALE, pair.Name, item.Id)
			self.logWarn("trust detail not found in redis and database, delete from waiting list, tid: %d", item.Id)
			continue
		}

		if _, ok := result.PassiveAccounts[seller.Uid]; !ok {
			result.PassiveAccounts[seller.Uid] = new(structs.Account)
		}

		// orderLogs := NewOrderLogs()
		passiveResult := &structs.OneTrust{
			TrustId: 		seller.Id,
			Uid: 			seller.Uid,
			OriginalTrustCoin: copyWithPoint(seller),
		}

		result.PassiveTrusts = append(result.PassiveTrusts, passiveResult)

		sellerNumber, _ := decimal.NewFromString(seller.Number)
		sellerAvailable, _ := decimal.NewFromString(seller.NumberAvailable)
		sellerPrice, _ := decimal.NewFromString(seller.Price)

		var min decimal.Decimal
		// 买家和卖家剩余数量比较
		if trustAvailable.GreaterThanOrEqual(sellerAvailable) {
			min = sellerAvailable
			passiveResult.TrustDealStatus = structs.TRUST_STATUS_ALL
		} else {
			min = trustAvailable
			passiveResult.TrustDealStatus = structs.TRUST_STATUS_PARTIALLY
		}

		self.logInfo("minimum transaction quantity, min:%s, passive status: %d",
			min.StringFixedBank(int32(pair.FloatNumber)), passiveResult.TrustDealStatus)

		// 买家还需要购买的数量，如果全部购买，数量为0.0
		trustAvailable = trustAvailable.Sub(min)
		self.logInfo("active trust left number available: %s", trustAvailable.StringFixedBank(10))

		// 交易额总量 = 交易数量 * 交易价格
		// 成交价按被动用户价格成交
		total := min.Mul(sellerPrice)

		totalFee := total.Mul(sellRate)
		volFee := min.Mul(buyRate)

		activeTotal := total.Sub(totalFee)
		activeVol := min.Sub(volFee)
		passiveTotal := total.Sub(totalFee)

		var isSellerFree, isBuyerFree bool

		self.ctx.Data.mu.Lock()
		if _, ok := self.ctx.Data.NoFee[trust.Uid]; ok {
			isBuyerFree = true
		}

		if _, ok := self.ctx.Data.NoFee[seller.Uid]; ok {
			isSellerFree = true
		}
		self.ctx.Data.mu.Unlock()

		// 买家是否免税
		if isBuyerFree {
			activeTotal = total
			activeVol = min
			self.logInfo("buyer is no tax, uid: %d, pay out(%s): %v, get in(%s): %v", trust.Uid, pair.CoinTo, total, pair.CoinFrom, min)
		}

		// 卖家是否免税
		if isSellerFree {
			passiveTotal = total
			self.logInfo("seller is no tax, uid: %d, get in(%s): %v", trust.Uid, pair.CoinTo, passiveTotal)
		}

		// 交易差额返还给用户
		priceDiff := min.Mul(trustPrice).Sub(total)
		if priceDiff.LessThan(decimal.Zero) {
			priceDiff = decimal.Zero
		}

		self.logInfo("price diff(need to back to buyer account), uid: %d, diff: %v", trust.Uid, priceDiff)
		toLock := decimal.NewFromFloat(-1).Mul(total).Sub(priceDiff)
		result.ActiveAccount.ToLock = result.ActiveAccount.ToLock.Add(toLock)
		result.ActiveAccount.ToOver = result.ActiveAccount.ToOver.Add(priceDiff)
		result.ActiveAccount.FromOver = result.ActiveAccount.FromOver.Add(activeVol)

		// 买家ID与卖家ID是否相同
		ToOver := decimal.NewFromFloat(1).Mul(passiveTotal)
		FromLock := decimal.NewFromFloat(-1).Mul(min)
		if seller.Uid != trust.Uid {
			result.PassiveAccounts[seller.Uid].ToOver = result.PassiveAccounts[seller.Uid].ToOver.Add(ToOver)
			result.PassiveAccounts[seller.Uid].FromLock = result.PassiveAccounts[seller.Uid].FromLock.Add(FromLock)
		} else {
			result.ActiveAccount.ToOver = result.ActiveAccount.ToOver.Add(activeTotal)
			result.ActiveAccount.FromLock = result.ActiveAccount.FromLock.Sub(min)
		}

		// 单笔交易记录
		orderLogs := &structs.OrderLogs{
			BuyUid: 	trust.Uid,
			SaleUid: 	seller.Uid,
			DealNumber: min,
			DealPrice: 	sellerPrice,
			DealTotal: 	total,

			BuyerFromOver: 	min,
			BuyerToOver: 	priceDiff,
			BuyerToLock: 	toLock,

			SellerFromLock:	FromLock,
			SellerToOver: 	total,

			Order:    	new(structs.OrderCoin),
			Finances: 	make([]*structs.OrderCoinFinance, 0),
		}

		// 卖家税，用户不免税且税率大于0
		if !isSellerFree && sellRate.Cmp(decimal.Zero) == 1 {
			self.logInfo("seller is not free, uid: %d fee: %v", seller.Id, sellRate.StringFixedBank(16))
			orderLogs.Finances = append(orderLogs.Finances, createOrderFinance(seller.Uid,
				OFFICIAL_UID,
				trust.CoinFrom,
				trust.CoinTo,
				trust.CoinTo,
				formatDecimal2String(totalFee, 16),
				model.FINANCE_TYPE_SALE))

			if fee, ok := result.TotalFeeNumber[trust.CoinTo]; !ok {
				result.TotalFeeNumber[trust.CoinTo] = totalFee
			} else {
				result.TotalFeeNumber[trust.CoinTo] = fee.Add(totalFee)
			}

			// 单笔卖家税
			orderLogs.SellerFee = totalFee
		}

		// 买家税，用户不免税且税率大于0
		if !isBuyerFree && buyRate.GreaterThan(decimal.Zero) {
			self.logInfo("buyer is not free, uid: %d, fee: %v", trust.Uid, volFee.StringFixedBank(16))
			orderLogs.Finances = append(orderLogs.Finances, createOrderFinance(trust.Uid,
				OFFICIAL_UID,
				trust.CoinFrom,
				trust.CoinTo,
				trust.CoinFrom,
				formatDecimal2String(volFee, 16),
				model.FINANCE_TYPE_BUY))

			if fee, ok := result.TotalFeeNumber[trust.CoinFrom]; !ok {
				result.TotalFeeNumber[trust.CoinFrom] = volFee
			} else {
				result.TotalFeeNumber[trust.CoinFrom] = fee.Add(volFee)
			}

			// 单笔买家税
			orderLogs.BuyerFee = volFee
		}

		passiveResult.DealNumber = min
		passiveResult.TrustCoin = copyTrustCoin(seller,
			formatDecimal2String(sellerAvailable.Sub(min), pair.FloatNumber),
			formatDecimal2String(sellerNumber.Sub(sellerAvailable).Add(min), pair.FloatNumber),
			passiveResult.TrustDealStatus)

		// order
		orderLogs.Order = &structs.OrderCoin{
			BuyTrustId:  trust.Id,
			BuyUid:      trust.Uid,
			SaleTrustId: seller.Id,
			SaleUid:     seller.Uid,
			CoinFrom:    trust.CoinFrom,
			CoinTo:      trust.CoinTo,
			Number:      formatDecimal2String(min, pair.FloatNumber),
			Price:       formatDecimal2String(sellerPrice, pair.FloatPrice),
			CreateTime:  int(time.Now().Unix()),
			UpdateTime:  time.Now(),
		}

		result.OrderLogs = append(result.OrderLogs, orderLogs)

		// delete from waiting list
		if passiveResult.TrustDealStatus == structs.TRUST_STATUS_ALL {
			self.logInfo("passive trust deal all, remove from wait list, tid: %d", item.Id)
			if _, err := removeTrustFromWaitWithoutMulti(conn, structs.TASK_SALE, pair.Name, item.Id); err != nil {
				self.logError("remove trust from waiting list, tid: %d, price: %s", item.Id, item.Price.StringFixedBank(10))
				return err
			}
			self.doneWaiting = append(self.doneWaiting, item)
		}

		result.IsDealed = true
		if trustAvailable.Cmp(decimal.Zero) == 0 {
			result.ActiveTrust.TrustDealStatus = structs.TRUST_STATUS_ALL
			self.logInfo("active trust deal all and break the loop, status: %d", model.Status_All)
			break
		}
	}

	if trustAvailable.GreaterThan(decimal.Zero) && result.ActiveTrust.TrustDealStatus != structs.TRUST_STATUS_ALL {
		self.logInfo("active trust deal partially at the end of loop, status: %d", model.Status_Partially)
		result.ActiveTrust.TrustDealStatus = structs.TRUST_STATUS_PARTIALLY
	}

	// 包装 trust coin
	result.ActiveTrust.TrustCoin = copyTrustCoin(trust,
		formatDecimal2String(trustAvailable, pair.FloatNumber),
		formatDecimal2String(trustNumber.Sub(trustAvailable), pair.FloatNumber),
		result.ActiveTrust.TrustDealStatus)

	if trustAvailable.GreaterThan(decimal.Zero) && counter == DEFAULT_WAIT_COUNTS {
		self.logInfo("--> get in the inner loop")
		err := self.loop(conn, result.ActiveTrust.TrustCoin, result, pair)
		self.logInfo("<-- get out of the inner loop")
		if err != nil {
			self.logError("out of the inner loop with error, msg: %s", err)
			return err
		}
	}

	return nil
}

func (self *BuyHandler) doTrust(conn redis.Conn, trust structs.TrustCoin, result *structs.Results, pair structs.CoinPair) error {
	err := self.loop(conn, &trust, result, pair)
	if err != nil || !result.IsDealed {
		result.AddActiveTrustToSet = true
	}
	return err
}

func (self BuyHandler) logInfo(format string, v ...interface{})  {
	log.Infof("["+self.name+"] " + format, v...)
}

func (self BuyHandler) logError(format string, v ...interface{})  {
	log.Errorf("["+self.name+"] " + format, v...)
}

func (self BuyHandler) logWarn(format string, v ...interface{})  {
	log.Warnf("["+self.name+"] " + format, v...)
}

type SaleHandler struct{
	name 				string
	doneWaiting 		[]trustItem
	startTime 			time.Time
	ctx 				*Context
}

func (self *SaleHandler) handler(trust structs.TrustCoin, taskType structs.TaskType, worker *Worker) {
	self.name = worker.coinPair.Name
	if taskType == structs.TASK_SALE {
		self.handlerSale(trust, taskType, worker)
	} else {
		handlerCancel(trust, taskType, worker)
	}
}

func (self *SaleHandler) handlerSale(trust structs.TrustCoin, taskType structs.TaskType, worker *Worker)  {

	self.logInfo("+++++ Start Handler Sale Trust +++++")
	self.logInfo("active sale trust info, tid: %d, uid: %d, number_available: %s, price: %s",
		trust.Id, trust.Uid, trust.NumberAvailable, trust.Price)

	self.startTime = time.Now()

	var cacheOptSuccess bool
	var err error
	self.ctx = worker.ctx
	self.doneWaiting = make([]trustItem, 0)

	conn := worker.ctx.GetOteRedis().Get()
	results := structs.NewResults(worker.coinPair.CoinFrom, worker.coinPair.CoinTo, structs.TASK_SALE)

	defer func() {
		// 失败保护，如果Redis操作失败导致回滚，将该条委托申请加入待匹配列表
		dbHandler := NewHandlerDB(worker.coinPair)
		if !cacheOptSuccess {
			oteLog := NewOteLog(results, taskType)
			if err != nil {
				oteLog.ErrorCode = model.OTE_LOG_ERRCODE_REDIS
				oteLog.ErrorMsg = err.Error()
			}

			if _, err := dbHandler.SaveOteLog(oteLog); err != nil {
				self.logError("save ote log error, msg: %s", err.Error())
			}

			_, err := addTrustToWaitWithMulti(conn, structs.TASK_SALE, worker.coinPair.Name, trust.Id, trust.Price)
			if err != nil {
				data, _ := resultToString(results)
				self.logError("redis rollback and add sale trust to wait failed, tid: %d, result: %v", trust.Id, data)
			}

			// 删除的被动单添加到wait列表
			for _, item := range self.doneWaiting {
				_, err := addTrustToWaitWithMulti(conn, structs.TASK_BUY, worker.coinPair.Name, item.Id, item.Price.StringFixedBank(10))
				if err != nil {
					self.logError("redis rollback and add buy trust to wait failed, tid: %d, passiveId: %v, err: %v", trust.Id, item.Id, err)
				}
			}
		}

		if cacheOptSuccess && results.AddActiveTrustToSet {
			if _, err := dbHandler.SetTrustCoinIsNewToOld(results.ActiveTrust.TrustId); err != nil {
				self.logError("set trust coin to old status failed, err: %s", err.Error())
			}
		}
		conn.Close()
	}()

	activeResult := &structs.OneTrust{
		TrustId: 			trust.Id,
		Uid: 				trust.Uid,
		OriginalTrustCoin: 	copyWithStruct(trust),
		TrustDealStatus: 	structs.TRUST_STATUS_NOT}


	activeAccount := new(structs.Account)

	results.ActiveTrust = activeResult
	results.ActiveAccount = activeAccount

	err = self.doTrust(conn, trust, results, worker.coinPair)
	if err != nil {
		self.logError("do sale trust error, msg: %s", err.Error())
	}

	// do redis
	if results.AddActiveTrustToSet {
		// 添加委托单到卖家SET
		_, err = addTrustToWaitWithoutMulti(conn, structs.TASK_SALE, worker.coinPair.Name, trust.Id, trust.Price)
		if err != nil {
			self.logError("save trust sale error, tid: %d, msg: %s", trust.Id, err.Error())
		}
		self.logInfo("save trust sale success. tid: %d", trust.Id)
	}

	if !results.IsDealed {
		self.logInfo("not matched and return, tid: %d", trust.Id)
		cacheOptSuccess = true
		return
	}

	conn.Do("MULTI")

	// 1. 主动单
	if results.ActiveTrust.TrustDealStatus == structs.TRUST_STATUS_PARTIALLY {
		// 部分交易
		// 添加到 redis wait set
		if _, err = addTrustToWaitWithMulti(conn, structs.TASK_SALE, worker.coinPair.Name,
			trust.Id, trust.Price); err != nil {
			self.logError("set trust buy error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}
		self.logInfo("add trust to wait list success, tid: %d, status: %d", trust.Id, structs.TRUST_STATUS_PARTIALLY)

		// modify detail info
		// modify user trust info
		if _, err = updateTrustAndUserDetailAndWithMulti(conn, worker.coinPair.Name, structs.TASK_SALE,
			trust.Id, trust.Uid, results.ActiveTrust.TrustCoin); err != nil {
			self.logError("update trust and user detail error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}
		self.logInfo("update trust in detail and user list success, tid: %d, status: %d", trust.Id, structs.TRUST_STATUS_PARTIALLY)

	} else {
		// 全部交易
		if _, err = removeTrustDetailWithMulti(conn, worker.coinPair.Name, structs.TASK_SALE,
			trust.Id, trust.Uid); err != nil {
			self.logError("remove trust detail error, msg: %s", err.Error())
			conn.Do("DISCARD")
			return
		}

		// 保存到历史记录
		saveTrustToHistoryDone(conn, worker.coinPair.Name, results.ActiveTrust.Uid, results.ActiveTrust.TrustCoin)
		self.logInfo("remove trust detail success, tid: %d, status: %d", trust.Id, structs.TRUST_STATUS_ALL)
	}

	// 2. 被动单
	for _, passiveTrust := range results.PassiveTrusts {
		if passiveTrust.TrustDealStatus == structs.TRUST_STATUS_PARTIALLY {
			// 被动单部分成交
			if _, err = updateTrustAndUserDetailAndWithMulti(conn, worker.coinPair.Name, structs.TASK_BUY,
				passiveTrust.TrustId, passiveTrust.Uid, passiveTrust.TrustCoin); err != nil {
				self.logError("update passive trust user detail error, msg: %s", err.Error())
				conn.Do("DISCARD")
				return
			}
			self.logInfo("update passive trust success, tid: %d, status: %d", trust.Id, structs.TRUST_STATUS_PARTIALLY)
		} else {
			// 被动单全部成交
			if _, err = removeTrustDetailWithMulti(conn, worker.coinPair.Name, structs.TASK_BUY,
				passiveTrust.TrustId, passiveTrust.Uid); err != nil {
				self.logError("remove trust detail error, msg: %s", err.Error())
				conn.Do("DISCARD")
				return
			}
			self.logInfo("remove trust detail success, tid: %d, status: %d", trust.Id, structs.TRUST_STATUS_ALL)

			saveTrustToHistoryDone(conn, worker.coinPair.Name, passiveTrust.Uid, passiveTrust.TrustCoin)
		}
	}

	conn.Do("EXEC")
	cacheOptSuccess = true
	results.RedisOptSuccess = true

	self.logInfo("end, take time: %s", time.Since(self.startTime).String())
	self.logInfo("+++ End Handler Sale Trust +++")

	worker.handlerResult(results)
	// worker.result <- results
}

func (self *SaleHandler) loop(conn redis.Conn, coin *structs.TrustCoin, result *structs.Results, pair structs.CoinPair) error {

	trustNumber, _ := decimal.NewFromString(coin.Number)
	trustAvailable, _ := decimal.NewFromString(coin.NumberAvailable)

	saleRate, _ := decimal.NewFromString(pair.TradeSaleRate)
	buyRate, _ := decimal.NewFromString(pair.TradeBuyRate)

	items, err := getMatchedBuyTrustsFromRedis(conn, coin.Price, pair.Name)
	if err != nil {
		self.logError("no matched buy items, getItems error, msg: %s", err.Error())
		return err
	}

	if len(items) == 0 {
		self.logInfo("no matched buy items, return and save to wait list, tid: %d", coin.Id)
		return nil
	}

	// 排序
	sort.Sort(TrustItemSlice(items))

	self.logInfo("get buy trust from wait list success, len: %d", len(items))

	counter := 0

	for _, item := range items {
		counter++
		self.logInfo(">>>>> the %d times in loop <<<<<<", counter)

		buyer, err := getTrustDetailFromRedis(conn, structs.TASK_BUY, pair.Name, item.Id)
		if err != nil {
			self.logError("get trust detail failed, msg: %s", err.Error())
			continue
		}

		self.logInfo("get buy trust: tid: %d, uid: %d, number: %s, number available: %s, price: %s, status: %d",
			buyer.Id, buyer.Uid, buyer.Number, buyer.NumberAvailable, buyer.Price, buyer.Status)

		if buyer.Id == 0 || buyer.Status == model.Status_All || buyer.Status == model.Status_Revoke {
			removeTrustFromWaitWithoutMulti(conn, structs.TASK_BUY, pair.Name, item.Id)
			self.logWarn("trust detail not found in wait list and database or status is not right, tid: %d", buyer.Id)
			continue
		}

		passiveResult := &structs.OneTrust{
			TrustId: 			buyer.Id,
			Uid: 				buyer.Uid,
			OriginalTrustCoin: 	copyWithPoint(buyer),
			TrustDealStatus: 	structs.TRUST_STATUS_NOT,
		}

		result.PassiveTrusts = append(result.PassiveTrusts, passiveResult)

		// passive asset
		if _, ok := result.PassiveAccounts[buyer.Uid]; !ok {
			result.PassiveAccounts[buyer.Uid] = new(structs.Account)
		}

		buyerNumber, _ := decimal.NewFromString(buyer.Number)
		buyerAvailable, _ := decimal.NewFromString(buyer.NumberAvailable)
		buyerPrice, _ := decimal.NewFromString(buyer.Price)

		var min decimal.Decimal
		// 买家和卖家剩余数量比较
		if trustAvailable.GreaterThanOrEqual(buyerAvailable) {
			min = buyerAvailable
			passiveResult.TrustDealStatus = structs.TRUST_STATUS_ALL
		} else {
			min = trustAvailable
			passiveResult.TrustDealStatus = structs.TRUST_STATUS_PARTIALLY
		}

		self.logInfo("minimum transaction quantity, min:%s, passive status: %d",
			min.StringFixedBank(int32(pair.FloatNumber)), passiveResult.TrustDealStatus)

		// 买家还需要购买的数量，如果全部购买，数量为0
		trustAvailable = trustAvailable.Sub(min)
		self.logInfo("active left number available: %s", trustAvailable.StringFixedBank(10))

		total := min.Mul(buyerPrice)
		totalFee := total.Mul(saleRate)

		activeTotal := total.Sub(totalFee)
		volFee := min.Mul(buyRate)

		activeVol := min.Sub(volFee)
		passiveVol := min.Sub(volFee)

		var isSellerFree, isBuyerFree bool
		self.ctx.Data.mu.Lock()
		if _, ok := self.ctx.Data.NoFee[coin.Uid]; ok {
			isSellerFree = true
		}
		if _, ok := self.ctx.Data.NoFee[buyer.Uid]; ok {
			isBuyerFree = true
		}
		self.ctx.Data.mu.Unlock()

		// 卖家是否免税 (主动用户)
		if isSellerFree {
			activeTotal = total
			activeVol = min
			self.logInfo("seller is no tax, uid: %d, sale out(%s): %s", buyer.Uid, pair.CoinFrom, min)
		}

		// 买家是否免税 (被动用户)
		if isBuyerFree {
			passiveVol = min
			self.logInfo("buyer is no tax, uid: %d, pay out(%s): %v, get in(%s): %v", buyer.Uid, pair.CoinTo, total, pair.CoinFrom, min)
		}

		// active user 账户余额
		result.ActiveAccount.ToOver = result.ActiveAccount.ToOver.Add(activeTotal)
		result.ActiveAccount.FromLock = result.ActiveAccount.FromLock.Sub(min)
		ToLock := decimal.NewFromFloat(-1).Mul(total)
		if coin.Uid != buyer.Uid {
			result.PassiveAccounts[buyer.Uid].FromOver = result.PassiveAccounts[buyer.Uid].FromOver.Add(passiveVol)
			result.PassiveAccounts[buyer.Uid].ToLock = result.PassiveAccounts[buyer.Uid].ToLock.Add(ToLock)
		} else {
			result.ActiveAccount.ToLock = result.ActiveAccount.ToLock.Sub(total)
			result.ActiveAccount.FromOver = result.ActiveAccount.FromOver.Add(activeVol)
		}

		// 单笔记录
		orderLogs := &structs.OrderLogs{
			BuyUid: 		buyer.Uid,
			SaleUid: 		coin.Uid,
			DealNumber: 	min,
			DealPrice: 		buyerPrice,
			DealTotal: 		total,
			SellerFromLock: min.Mul(decimal.NewFromFloat(-1)),
			SellerToOver: 	total,
			BuyerFromOver: 	min,
			BuyerToLock: 	ToLock,
			Order: 			new(structs.OrderCoin),
			Finances: 		make([]*structs.OrderCoinFinance, 0)}

		// 买家税
		if buyRate.GreaterThan(decimal.Zero) && !isBuyerFree {
			self.logInfo("buyer uid is not free, uid: %d, fee: %s", buyer.Uid, volFee.StringFixedBank(16))
			orderLogs.Finances = append(orderLogs.Finances, createOrderFinance(buyer.Uid,
				OFFICIAL_UID,
				coin.CoinFrom,
				coin.CoinTo,
				coin.CoinFrom,
				formatDecimal2String(volFee, 16),
				model.FINANCE_TYPE_BUY))

			if fee, ok := result.TotalFeeNumber[coin.CoinFrom]; !ok {
				result.TotalFeeNumber[coin.CoinFrom] = volFee
			} else {
				result.TotalFeeNumber[coin.CoinFrom] = fee.Add(volFee)
			}

			orderLogs.BuyerFee = volFee
		}

		// 卖家税
		if saleRate.GreaterThan(decimal.Zero) && !isSellerFree {
			self.logInfo("seller uid is not free, uid: %d, fee: %s", coin.Uid, totalFee.StringFixedBank(16))
			orderLogs.Finances = append(orderLogs.Finances, createOrderFinance(coin.Uid,
				OFFICIAL_UID,
				coin.CoinFrom,
				coin.CoinTo,
				coin.CoinTo,
				formatDecimal2String(totalFee, 16),
				model.FINANCE_TYPE_SALE))

			if fee, ok := result.TotalFeeNumber[coin.CoinTo]; !ok {
				result.TotalFeeNumber[coin.CoinTo] = totalFee
			} else {
				result.TotalFeeNumber[coin.CoinTo] = fee.Add(totalFee)
			}

			orderLogs.SellerFee = totalFee
		}

		passiveResult.DealNumber = min
		passiveResult.TrustCoin = copyTrustCoin(buyer,
			formatDecimal2String(buyerAvailable.Sub(min), pair.FloatPrice),
			formatDecimal2String(buyerNumber.Sub(buyerAvailable).Add(min), pair.FloatPrice),
			passiveResult.TrustDealStatus)

		// order
		orderLogs.Order = &structs.OrderCoin{
			BuyTrustId:  buyer.Id,
			BuyUid:      buyer.Uid,
			SaleTrustId: coin.Id,
			SaleUid:     coin.Uid,
			CoinFrom:    coin.CoinFrom,
			CoinTo:      coin.CoinTo,
			Number:      formatDecimal2String(min, pair.FloatNumber),
			Price:       formatDecimal2String(buyerPrice, pair.FloatPrice),
			CreateTime:  int(time.Now().Unix()),
			UpdateTime:  time.Now(),
		}

		result.OrderLogs = append(result.OrderLogs, orderLogs)

		if passiveResult.TrustDealStatus == structs.TRUST_STATUS_ALL {
			self.logInfo("passive trust deal all, remove from wait list, tid: %d", item.Id)
			if _, err := removeTrustFromWaitWithoutMulti(conn, structs.TASK_BUY, pair.Name, item.Id); err != nil {
				self.logError("remove trust from waiting list, tid: %d, err: %s", item.Id, err.Error())
				return err
			}
			self.doneWaiting = append(self.doneWaiting, item)
		}

		result.IsDealed = true
		if trustAvailable.Cmp(decimal.Zero) == 0 {
			result.ActiveTrust.TrustDealStatus = structs.TRUST_STATUS_ALL
			self.logInfo("active trust deal all and break the loop, tid: %d, status: %d", coin.Id, model.Status_All)
			break
		}
	}

	if result.ActiveTrust.TrustDealStatus != structs.TRUST_STATUS_ALL && trustAvailable.GreaterThan(decimal.Zero) {
		self.logInfo("active trust deal partially at the end of the loop, status: %d", model.Status_Partially)
		result.ActiveTrust.TrustDealStatus = structs.TRUST_STATUS_PARTIALLY
	}

	// 包装 trust coin
	result.ActiveTrust.TrustCoin = copyTrustCoin(coin,
		formatDecimal2String(trustAvailable, pair.FloatNumber),
		formatDecimal2String(trustNumber.Sub(trustAvailable), pair.FloatNumber),
		result.ActiveTrust.TrustDealStatus)

	if trustAvailable.GreaterThan(decimal.Zero) && counter == DEFAULT_WAIT_COUNTS {
		self.logInfo("--> get in the inner loop")
		err := self.loop(conn, result.ActiveTrust.TrustCoin, result, pair)
		self.logInfo("<-- get out of the inner loop")
		if err != nil {
			self.logError("out of the inner loop with error, msg: %s", err.Error())
			return err
		}
	}

	return nil
}

func (self *SaleHandler) doTrust(conn redis.Conn, coin structs.TrustCoin, result *structs.Results, pair structs.CoinPair) error {
	err := self.loop(conn, &coin, result, pair)
	if err != nil || !result.IsDealed {
		result.AddActiveTrustToSet = true
	}
	return err
}

func (self SaleHandler) logInfo(format string, v ...interface{})  {
	log.Infof("["+self.name+"] " + format, v...)
}

func (self SaleHandler) logError(format string, v ...interface{})  {
	log.Errorf("["+self.name+"] " + format, v...)
}

func (self SaleHandler) logWarn(format string, v ...interface{})  {
	log.Warnf("["+self.name+"] " + format, v...)
}

func handlerCancel(trust structs.TrustCoin, taskType structs.TaskType, worker *Worker) {
	conn := worker.ctx.GetOteRedis().Get()
	defer conn.Close()

	// check is waiting
	if ok, err := checkIsWaitingAndRemoveIfExists(conn, structs.TaskType(trust.Flag), worker.coinPair.Name, trust.Id); !ok {
		log.Infof("check trust is waiting error, msg: %v", err)
		return
	}

	_, err := removeTrustDetailIfExists(conn, structs.TaskType(trust.Flag), worker.coinPair.Name, trust.Id, trust.Uid)
	if err != nil {
		log.Infof("remove trust detail error, msg: %s", err.Error())
	}

	result := structs.NewResults(trust.CoinFrom, trust.CoinTo, taskType)
	result.ActiveTrust.OriginalTrustCoin = copyWithStruct(trust)
	worker.handlerCancel(result)
	// worker.result <- result
}